import datetime
import cv2
import sqlite3
import os
from src.infer import Detector
from src.stream import VideoStream
from src.login import login_page, register_page, create_users_table
import json
import asyncio
import websockets
import base64
import streamlit.components.v1 as components
import streamlit as st
import pandas as pd
import socket
from src.basic_infer import *
model=None
def is_port_in_use(port, host='127.0.0.1'):
    """检查端口是否占用"""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.settimeout(1)
        try:
            print("------------ws已开启")
            s.connect((host, port))
            return True
        except socket.error:
            print("------------ws未开启")
            return False


video_streams = {i: None for i in range(1, 10)}

def setup_database():
    """初始化数据库"""
    db_dir, db_file = "db", "behavior_detection.db"
    os.makedirs(db_dir, exist_ok=True)
    conn = sqlite3.connect(os.path.join(db_dir, db_file))
    c = conn.cursor()
    c.executescript(
        """
        CREATE TABLE IF NOT EXISTS events (timestamp TEXT, camera_id INTEGER, details TEXT, FOREIGN KEY (camera_id) REFERENCES cameras (id));
        CREATE TABLE IF NOT EXISTS cameras (id INTEGER PRIMARY KEY, url TEXT);
        CREATE TABLE IF NOT EXISTS event_images (image_id INTEGER PRIMARY KEY AUTOINCREMENT, event_id INTEGER, image_data BLOB, timestamp TEXT, FOREIGN KEY (event_id) REFERENCES events(rowid));
    """
    )
    for i in range(1, 10):
        c.execute("INSERT OR IGNORE INTO cameras (id, url) VALUES (?, '')", (i,))
    conn.commit()
    conn.close()


setup_database()


def insert_event(timestamp, camera_id, details=None):
    """插入异常事件时间戳和相机id到数据库"""
    conn = sqlite3.connect(os.path.join("db", "behavior_detection.db"))
    c = conn.cursor()
    if details:
        c.execute(
            "INSERT INTO events (timestamp, camera_id, details) VALUES (?, ?, ?)",
            (timestamp, camera_id, details),
        )
    else:
        c.execute(
            "INSERT INTO events (timestamp, camera_id) VALUES (?, ?)",
            (timestamp, camera_id),
        )
    event_id = c.lastrowid
    conn.commit()
    conn.close()
    return event_id


def update_event(event_id, duration, avg_confidence):
    """更新异常事件，添加详情"""
    conn = sqlite3.connect(os.path.join("db", "behavior_detection.db"))
    c = conn.cursor()
    details = (
        f"检测到方向盘抢夺事件，持续时间：{duration:.2f}秒，平均可能性：{avg_confidence:.2f}%"
    )
    c.execute("UPDATE events SET details = ? WHERE rowid = ?", (details, event_id))
    conn.commit()
    conn.close()


async def handle_camera(websocket, path):
    """视频帧显示和预测"""
    event_id = None
    camera_id = path.strip("/")
    print(f'ws{path}连接,{len(video_streams)}')

    video_stream = video_streams.get(int(camera_id[3:]))
    if not video_stream:
        await websocket.close()
        print(f'ws{path}下没有视频流,关闭')
        return
    print(f'ws{path}已加载-流id{int(camera_id[3:])}')
    current_frame_time=datetime.datetime.now()
    detector = Detector("model/yolov10.pt")
    event_details, last_event_time, event_start_time = [], None, None
    event_image_count = {}
    last_store_time = None
    try:
        while websocket.open:
            frame = video_stream.get_frame()
            if frame is None and(datetime.datetime.now() - current_frame_time  ).total_seconds() >= 5:
                break
            elif frame is None:
                continue
            frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            best_result, confidence, label = detector.predict(frame_rgb)
            current_time = datetime.datetime.now()
            print(best_result,label)
            if best_result == 1 and confidence > 0.991:
                if event_id is None:
                    event_start_time = current_time
                    event_id = insert_event(
                        event_start_time.isoformat(), int(camera_id[3:])
                    )
                    event_image_count[event_id] = 0
                last_event_time = current_time
                event_details.append(confidence * 100)
                if confidence > 0.991:
                    print("y")
                    if event_image_count[event_id] < 5:
                        if (
                            last_store_time is None
                            or (current_time - last_store_time).total_seconds() >= 1
                        ):
                            store_image(
                                event_id, frame_rgb, event_start_time.isoformat()
                            )
                            event_image_count[event_id] += 1
                            last_store_time = current_time
            elif (
                event_id is not None
                and (current_time - last_event_time).total_seconds() > 2
            ):
                duration = (last_event_time - event_start_time).total_seconds()
                avg_confidence = sum(event_details) / len(event_details)
                update_event(event_id, duration, avg_confidence)
                event_id = None
                event_details = []
            _, buffer = cv2.imencode(".jpg", frame_rgb)
            frame_base64 = base64.b64encode(buffer).decode("utf-8")
            data = {
                "index": camera_id,
                "result": best_result,
                "confidence": confidence * 100,
                "frame": frame_base64,
            }
            await websocket.send(json.dumps(data))
            await asyncio.sleep(0.033)
    finally:
        if event_id is not None:
            duration = (last_event_time - event_start_time).total_seconds()
            avg_confidence = sum(event_details) / len(event_details)
            update_event(event_id, duration, avg_confidence)
        video_stream.close_stream()
        # del video_stream
        print(f'ws{path}关闭')
        # return


def store_image(event_id, frame, timestamp):
    """抓拍图片"""
    try:
        conn = sqlite3.connect(os.path.join("db", "behavior_detection.db"))
        c = conn.cursor()
        _, buffer = cv2.imencode(".jpg", frame)
        c.execute(
            "INSERT INTO event_images (event_id, image_data, timestamp) VALUES (?, ?, ?)",
            (event_id, buffer.tobytes(), timestamp),
        )
        conn.commit()
    except Exception as e:
        print(f"Error storing image: {e}")
    finally:
        conn.close()


def main_page():
    """首页"""
    st.title(f"欢迎，{st.session_state.get('username', 'Guest')}")

    now = datetime.datetime.now()
    st.write("当前日期和时间:", now.strftime("%Y年%m月%d日 %H:%M:%S"))

    conn = sqlite3.connect("db/behavior_detection.db")
    c = conn.cursor()

    c.execute("SELECT COUNT(*) FROM events")
    total_events = c.fetchone()[0]
    st.write("异常事件总数:", total_events)

    c.execute("SELECT timestamp, details FROM events ORDER BY timestamp DESC LIMIT 1")
    last_event = c.fetchone()
    if last_event:
        last_event_time = datetime.datetime.strptime(
            last_event[0], "%Y-%m-%dT%H:%M:%S.%f"
        ).strftime("%Y年%m月%d日 %H:%M:%S")
        last_event_details = last_event[1]
        st.write("最近一次异常事件发生时间:", last_event_time)
        st.write("事件详情:", last_event_details)
    else:
        st.write("没有记录的异常事件。")

    conn.close()

    if st.button("前往实时监控"):
        st.session_state["page"] = "home"
    if st.button("查看历史事件"):
        st.session_state["page"] = "events"
    if st.button("配置视频流"):
        st.session_state["page"] = "config"

    if st.session_state["page"] != "main":
        st.experimental_rerun()


def home_page():
    """实时监控页"""
    st.title("实时监控")
    update_streams_from_db()
    # for i in range(1,10):
    #     video_streams[i].reload()
    # html_code = None
    # with open("frontend/build/index.html", "r") as file:
    #     html_code = file.read()
    url = "http://localhost:3000"

    iframe_html = f'<iframe src="{url}" width="100%" height="600" frameborder="0" allowfullscreen></iframe>'
    print("实时监控页面加载中")

    components.html(iframe_html, height=600)
    print("实时监控页面已加载")
    # components.html(html_code, height=960)


def view_events():
    """显示历史事件"""
    st.title("历史异常事件")
    db_dir = "db"
    db_file = "behavior_detection.db"
    db_path = os.path.join(db_dir, db_file)

    if st.button("清空所有事件"):
        conn = sqlite3.connect(db_path)
        c = conn.cursor()
        c.execute("DELETE FROM events")
        c.execute("DELETE FROM event_images")
        conn.commit()
        conn.close()
        st.success("所有事件已清空。")

    enable_filter = st.checkbox("启用搜索/筛选")

    search_start_date = search_end_date = camera_id_filter = None

    if enable_filter:
        start_end_time = st.date_input(
            "选择起止时间",
            value=(
                datetime.date.today() - datetime.timedelta(days=7),
                datetime.date.today(),
            ),
            key="date_range",
        )
        if len(start_end_time) > 1:
            search_start_date, search_end_date = start_end_time
            camera_id_filter = st.text_input("摄像头ID", "")

    conn = sqlite3.connect(db_path)
    c = conn.cursor()

    query = "SELECT rowid, timestamp, camera_id, details FROM events"
    params = []
    conditions = []

    if search_start_date and search_end_date:
        conditions.append("DATE(timestamp) BETWEEN DATE(?) AND DATE(?)")
        params.extend([search_start_date, search_end_date])

    if camera_id_filter:
        conditions.append("camera_id = ?")
        params.append(camera_id_filter)

    if conditions:
        query += " WHERE " + " AND ".join(conditions)

    query += " ORDER BY timestamp DESC"
    c.execute(query, params)
    rows = c.fetchall()

    display_option = st.radio("选择展示方式", ("表格", "图片"))

    if display_option == "表格":
        if rows:
            df = pd.DataFrame(
                rows,
                columns=["事件ID", "时间", "摄像头ID", "详情"],
            )
            df["时间"] = pd.to_datetime(df["时间"]).dt.strftime("%Y-%m-%d %H:%M:%S")
            st.table(df)
        else:
            st.write("未找到事件。")
    else:
        for row in rows:
            event_id, timestamp, camera_id, details = row
            timestamp = datetime.datetime.strptime(
                timestamp, "%Y-%m-%dT%H:%M:%S.%f"
            ).strftime("%Y-%m-%d %H:%M:%S")
            st.subheader(f"时间: {timestamp} - 摄像头 ID: {camera_id}")
            st.write(details)

            c.execute(
                "SELECT image_data FROM event_images WHERE event_id = ?", (event_id,)
            )
            images = c.fetchall()
            if images:
                cols = st.columns(len(images))
                for col, (image_data,) in zip(cols, images):
                    col.image(image_data, caption=f"事件 ID: {event_id}", width=300)
            else:
                st.write("无可用图片")

    conn.close()


def update_streams_from_db():
    """丛数据库更新视频流"""
    global video_streams
    db_dir = "db"
    db_file = "behavior_detection.db"
    db_path = os.path.join(db_dir, db_file)
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    print("正在拉取新的视频流")
    for i in range(1, 10):
        c.execute("SELECT url FROM cameras WHERE id = ?", (i,))
        result = c.fetchone()

        if result[0]:
            print(f"第{i}个:{result[0]}")
            if video_streams[i]:
                print(f"正在关闭视频流:{result[0]}")
                video_streams[i].close_stream()
                del video_streams[i]
            print(f"拉取中...")
            video_streams[i] = VideoStream (result[0])
    conn.close()


def update_streams_url(id, url):
    global video_streams
    if video_streams[id]:
        video_streams[id].close_stream()
        del video_streams[id]
    video_streams[id] = VideoStream(url)


def config_streams_page():
    """视频流配置"""
    st.title("配置视频流地址")
    db_dir = "db"
    db_file = "behavior_detection.db"
    db_path = os.path.join(db_dir, db_file)
    conn = sqlite3.connect(db_path)
    c = conn.cursor()

    c.execute("SELECT id, url FROM cameras")
    current_urls = {id: url for id, url in c.fetchall()}

    new_urls = {}
    for i in range(1, 10):
        new_urls[i] = st.text_input(f"摄像头 {i} URL", current_urls.get(i, ""))
    print("进入更新页面")
    if st.button("保存更新"):
        try:
            for id, url in new_urls.items():
                c.execute("UPDATE cameras SET url = ? WHERE id = ?", (url, id))
            conn.commit()
            st.success("更新成功！")
        except Exception as e:
            st.error(f"更新失败：{e}")
        finally:
            conn.close()

    conn.close()


def pages():
    """页面切换和状态机管理"""
    global model
    st.set_page_config(layout="wide")

    st.markdown(
        """
        <style>
        .stButton>button {
            width: 100%;
        }
        </style>
        """,
        unsafe_allow_html=True,
    )
    create_users_table()
    if "logged_in" not in st.session_state:
        st.session_state["logged_in"] = False

    if st.session_state["logged_in"]:
        if not st.session_state.get("init_page"):
            st.session_state["page"] = "main"
            st.session_state["init_page"] = True
        if st.sidebar.button("主页", key="main"):
            st.session_state["page"] = "main"
        if st.sidebar.button("实时监控", key="home"):
            st.session_state["page"] = "home"
        if st.sidebar.button("历史事件", key="events"):
            st.session_state["page"] = "events"
        if st.sidebar.button("配置视频流", key="config"):
            st.session_state["page"] = "config"
        if st.sidebar.button("使用本机摄像头检测", key="webcam"):
            st.session_state["page"] = "webcam"
        if st.sidebar.button("使用图片检测", key="image"):
            st.session_state["page"] = "image"
        if st.sidebar.button("使用视频检测", key="video"):
            st.session_state["page"] = "video"
        if st.sidebar.button("退出登录", key="logout"):
            st.session_state["logged_in"] = False
            st.session_state["username"] = None
            st.session_state["page"] = "login"
            st.experimental_rerun()
        if not st.session_state.get("model_loaded"):
            model=load_model("model/yolov10.pt")
        if st.session_state.get("page") == "main":
            main_page()
        elif st.session_state.get("page") == "home":
            home_page()
        elif st.session_state.get("page") == "events":
            view_events()
        elif st.session_state.get("page") == "webcam":
            infer_uploaded_webcam(model)
        elif st.session_state.get("page") == "image":
            infer_uploaded_image(model)
        elif st.session_state.get("page") == "video":
            infer_uploaded_video(model)
        elif st.session_state.get("page") == "config":
            config_streams_page()
    else:
        if not st.session_state.get("init_login"):
            st.session_state["page"] = "login"
            st.session_state["init_login"] = True
        if st.sidebar.button("登录", key="login"):
            st.session_state["page"] = "login"
        if st.sidebar.button("注册", key="register"):
            st.session_state["page"] = "register"

        if st.session_state.get("page") == "login":
            login_page()
        elif st.session_state.get("page") == "register":
            register_page()


async def websocket_start():
    """ws"""
    async with websockets.serve(handle_camera, "0.0.0.0", 8764):
        global websocket_server_started
        print("WebSocket server started at ws://localhost:8764/")
        await asyncio.Future()


def run():
    pages()
    if is_port_in_use(8764):
        print(f"端口 8764 已被占用。")
    else:
        asyncio.run(websocket_start())

if __name__ == "__main__":
    run()
